home *** CD-ROM | disk | FTP | other *** search
- (c) Copyright 1989 Commodore-Amiga, Inc. All rights reserved.
- The information contained herein is subject to change without notice, and
- is provided "as is" without warranty of any kind, either express or implied.
- The entire risk as to the use of this information is assumed by the user.
-
-
- Disabling Sprite DMA From a Vertical Blank Interrupt
-
- by Adam Keith Levin
-
- An application program such as a screen blanking utility may need
- to disable sprite DMA in order to temporarily turn off sprites.
- The graphics macro OFF_SPRITE in the graphics library can be
- used for this. However, if sprite DMA is turned off with
- OFF_SPRITE at the exact instant that a sprite is being rendered,
- the sprite image may be "smeared" vertically on the display. The
- SpriteSwitch() program listed below provides a single function
- call which uses a vertical blank interrupt to either enable or
- disable sprite DMA cleanly, preventing this smearing.
-
-
- When You Don't Need SpriteSwitch()
-
- If you need to hide the mouse pointer only for your program, not
- for the entire system, you do not need this routine. Instead
- call Intuition's SetPointer() function with the address of a
- window belonging to your program, and a definition for a
- transparent pointer image. For example:
-
- SHORT height=1, width=16, x_offset=0, y_offset=0;
- USHORT *pointer_data;
- struct Window *this_window; /* A valid window pointer. */
-
- /* The smallest possible pointer definition, initialized to
- zeros. */
- pointer_data = (USHORT *)AllocMem(12L,MEMF_CHIP|MEMF_CLEAR|MEMF_PUBLIC);
- if (pointer_data)
- SetPointer(this_window, pointer_data, height, width, x_offset,
- y_offset);
- .
- .
- .
-
- if (pointer_data)
- {
- ClearPointer(this_window);
- FreeMem(pointer_data);
- }
-
-
- Using this method, the mouse-pointer will disappear whenever
- this_window is made active, and reappear when any other window is
- made active. (If you are opening a window solely for the
- purpose of turning off the pointer consider opening a BORDERLESS,
- BACKDROP window, which is unobtrusive.)
-
-
- When You DO Need SpriteSwitch()
-
- Shutting off Sprite DMA will prevent all sprites from being
- rendered, for the entire system. This is recommended only for
- screen-and-mouse blanker programs or programs that temporarily
- take over the system while running.
-
- In general, applications should use SpriteSwitch() as a
- substitute for the graphics macro OFF_SPRITE. The OFF_SPRITE
- macro might cause the sprite image to smear down the screen if
- it happens to take effect while the sprite is being rendered.
-
- The SpriteSwitch() function is listed below. An example call is
- also given in the main routine which is provided here only to
- exercise SpriteSwitch(). To shut off sprite DMA, you call
- SpriteSwitch() with the constant SWITCH_OFF. To turn on sprite
- DMA, call SpriteSwitch() with SWITCH_ON.
-
- SpriteSwitch() works by adding a server to the chain of VBLANK
- interrupt servers with the AddTOF() system function. The added
- server simply calls the graphics macro OFF_SPRITE or ON_SPRITE
- as appropriate. Since these macros are called from within the
- VBLANK interrupt, there is no chance that the sprite is being
- rendered at the same time the macro is called, hence, there is
- no way for the sprite to smear. After the sprite DMA is disabled
- (or enabled) SpriteSwitch() calls the system function RemTOF() to
- clear the server from the chain of VBLANK servers.
-
-
- Important Note
-
- The graphics library's VBLANK server depends upon address
- register A0 containing a pointer to the custom chips. If you add
- a server at a priority of ten (10) or greater, you must preserve
- the contents of A0 across the call, or otherwise insure that A0
- has the correct value. Since this is difficult to do when writing
- in C, it is recommended that VBLANK servers for applications
- such as SpriteSwitch() are given a priority of nine (9) or less.
-
-
- /* SpriteSwitch
- Cleanly turns Sprite DMA on or off using a Vertical-Blanking interrupt.
-
- Revision History:
- v1.0 Adam Keith Levin of CATS Created program.
-
- Lattice (v5.04) make: LC -b1 -cfist -L -v -y SpriteSwitch.c
- */
-
- /* Amiga System includes. */
- #include <exec/types.h>
- #include <exec/memory.h>
- #include <graphics/gfxmacros.h>
- #include <graphics/graphint.h>
- #include <hardware/custom.h>
- #include <hardware/dmabits.h>
- #include <libraries/dos.h>
-
- /* Lattice-specific includes. */
- #ifdef LATTICE
- #include <proto/all.h>
- #include <stdlib.h>
- #endif
-
- /* Amiga.lib prototypes. */
- VOID AddTOF(struct Isrvstr *, APTR, APTR);
- VOID RemTOF(struct Isrvstr *);
-
- /* SpriteSwitch request flags. */
- #define SWITCH_ON 0 /* Turn Sprite DMA on. */
- #define SWITCH_OFF 1 /* Turn Sprite DMA off. */
-
- /* Internal indicator that server has completed. */
- #define SWITCH_DONE ~0 /* DO NOT USE! */
-
- /* Error codes. */
- #define ERR_NONE 0 /* No problems encountered. */
- #define ERR_MEMORY 1 /* Not enough memory. */
- #define ERR_SIGNAL 2 /* Unable to allocate a signal bit. */
-
- /* The Switch_Data structure is used to pass data from the
- spriteSwitch() routine to the spriteSwitchServer() routine.
- */
- struct Switch_Data
- {
- UWORD state; /* One of the SpriteSwitch request flags. */
- struct Task *task; /* The task to be signalled. */
- ULONG signal; /* The signal to use. */
- };
-
-
- /* The SpriteSwitch Server.
- Calling "OFF_SPRITE" or "ON_SPRITE" during the Vertical-Blanking Interval
- assures that Sprite DMA will not be shut off while a Sprite is being
- rendered, so their imagery will not get "smeared".
- */
- int spriteSwitchServer(struct Switch_Data *switch_data)
- {
- extern struct Custom far custom; /* Needed by the _SPRITE macros. */
-
- /* Only run through this once. */
- if (SWITCH_DONE != switch_data->state)
- {
- switch((int)switch_data->state)
- {
- case (SWITCH_OFF):
- OFF_SPRITE;
- break;
- case (SWITCH_ON):
- ON_SPRITE;
- break;
- default:
- break;
- }
-
- /* Use the state variable to show that the server has already run. */
- switch_data->state = SWITCH_DONE;
-
- Signal(switch_data->task, switch_data->signal);
- }
-
- return(NULL);
- }
-
-
- /* SpriteSwitch.
- Called with a UWORD containing one of the Sprite request flags.
- It initializes a Switch_Data structure with said request flag,
- the task's address (from FindTask(NULL)) and a signal bit (from
- (AllocSignal(-1)). It installs the SpriteSwitch Server, Wait()s
- for it to signal that the request was completed, and removes it.
- Returns the constant ERR_NONE if successful, ERR_MEMORY if unable
- to allocate enough memory, and ERR_SIGNAL if unable to allocate
- a signal bit.
- */
- UWORD spriteSwitch(UWORD desired_state)
- {
- BYTE signal_bit;
- UWORD return_value;
- /* The Interrupt Server structure. When memory is allocated for it,
- all it's fields will be set to NULL, including the priority.
- If a priority other than zero were needed, it could be set
- before the AddTOF() call with:
- isrvstr.is_Node.ln_Pri = (BYTE)my_priority;
- Do not use a priority greater than 9! (Refer to article for reason).
- */
- struct Isrvstr *isrvstr = NULL;
-
- /* The Switch_Data structure. */
- struct Switch_Data *switch_data = NULL;
-
- isrvstr = (struct Isrvstr *)
- AllocMem((ULONG)sizeof(struct Isrvstr), MEMF_CLEAR|MEMF_PUBLIC);
- if (NULL != isrvstr)
- {
- switch_data = (struct Switch_Data *)
- AllocMem((ULONG)sizeof(struct Switch_Data), MEMF_PUBLIC);
- if (NULL != switch_data)
- {
- /* Attempt to allocate a signal bit. */
- signal_bit = AllocSignal(-1L);
- if (-1 != signal_bit)
- {
- /* Initialize the Switch_Data structure. */
- switch_data->state = desired_state;
- switch_data->task = FindTask(NULL);
- switch_data->signal = (1L << signal_bit);
-
- /* Add the server. */
- AddTOF(isrvstr, (APTR)spriteSwitchServer, (APTR)switch_data);
-
- /* Wait for it to signal that it has completed. */
- Wait(1L << signal_bit);
-
- /* Remove the server. */
- RemTOF(isrvstr);
-
- /* Free the signal bit. */
- FreeSignal(signal_bit);
-
- return_value = ERR_NONE;
- }
- else
- return_value = ERR_SIGNAL;
-
- FreeMem((VOID *)switch_data, (ULONG)sizeof(struct Switch_Data));
- }
- else
- return_value = ERR_MEMORY;
-
- FreeMem((VOID *)isrvstr, (ULONG)sizeof(struct Isrvstr));
- }
- else
- return_value = ERR_MEMORY;
-
- return(return_value);
- }
-
-
- /* stdio.h is needed by the main routine. */
- #include <stdio.h>
-
- /* This test routine exercises spriteSwitch() by turning off
- Sprite DMA for five seconds and then turning it back on.
- */
- VOID main(VOID)
- {
- UWORD exit_value;
-
-
- /* NOTE: You may need to OpenLibrary() the graphics library here if your
- compiler complains of an unresolved reference to "GfxBase".
- This is because the module in amiga.lib which contains AddTOF()
- and RemTOF() (which do not require the graphics library) also
- contains calls to routines which do require the graphics library.
- */
-
- exit_value = spriteSwitch(SWITCH_OFF);
- if (ERR_NONE == exit_value)
- {
- printf("Sprite DMA shut off.\n");
-
- Delay(5L * TICKS_PER_SECOND);
-
- exit_value = spriteSwitch(SWITCH_ON);
- if (ERR_NONE == exit_value)
- printf("Sprite DMA turned back on.\n");
- else
- {
- printf("Unable to allocate signal bit.\n");
- printf("Sprite DMA not turned back on.\n");
- }
- }
- else
- {
- printf("Unable to allocate signal bit.\n");
- printf("Sprite DMA not shut off.\n");
- }
-
- exit((int)exit_value);
- }
-
-
-
-